home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / HAPN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-28  |  11.8 KB  |  520 lines

  1. #ifdef MSDOS
  2. /*  Driver for HAPN-1 8273 card on PC
  3.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  4.  *  Modified Rx interrupt routine to prevent lockup
  5.  *  John Tanner VK2ZXQ 6th Feb 1988
  6.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  7.  */
  8. #include "global.h"
  9. #ifdef HAPN
  10. #include <dos.h>
  11. #include <stdarg.h>
  12. #include "timer.h"
  13. #include "mbuf.h"
  14. #include "iface.h"
  15. #include "pktdrvr.h"
  16. #include "netuser.h"
  17. #include "hapn.h"
  18. #include "ax25.h"
  19. #include "trace.h"
  20. #include "pc.h"
  21. #include "proc.h"
  22.  
  23. #if !defined(_lint)
  24. static char rcsid[] OPTIONAL = "$Id: hapn.c,v 1.11 1996/12/29 02:47:22 root Exp root $";
  25. #endif
  26.  
  27. static void cmd_8273 (int16 base,int cmd,int np,...);
  28. static int hapn_init (struct hapn *hp);
  29. static int hapn_raw (struct iface *iface,struct mbuf *bp);
  30. static int hapn_stop (struct iface *iface);
  31. static int hcdchk (int16 base);
  32. static void hrxint (struct hapn *hp);
  33. static void hrxgo (struct hapn *hp);
  34. static void htxint (void *p);
  35.  
  36. static struct hapn Hapn[NHAPN];
  37. static void (*H_handle[])() = { ha0vec };
  38. static int16 Nhapn;
  39.  
  40. /*  send command to the 8273
  41.  *  "base" = base port of 8273
  42.  *  "cmd"  = command byte
  43.  *  "np"   = number of parameter bytes
  44.  *  "p1"   = first parameter (parameters are int)
  45.  */
  46. static void
  47. cmd_8273(int16 base, int cmd, int np, ...)
  48. {
  49.     int p;
  50.     va_list ap;
  51.  
  52.     while(inportb(base+STA) & CBSY)
  53.         ;
  54.     outportb(base+CMD, cmd);
  55.  
  56.     va_start(ap,np);
  57.     while(np--){
  58.         while(inportb(base+STA) & CPBF)
  59.             ;
  60.         p = va_arg(ap,int);
  61.         outportb(base+PAR, p);
  62.     }
  63.     va_end(ap);
  64. }
  65.  
  66. /*  Start receiver of 8273 */
  67. static void
  68. hrxgo(hp)
  69. register struct hapn *hp;
  70. {
  71.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  72. }
  73.  
  74. /*  Interrupt service function.  Entered with hapn index
  75.  *  The "flag" variable is used in this routine to indicate a
  76.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  77.  *  the 8273 is reset.
  78.  */
  79. void
  80. haint(dev)
  81. int dev;
  82. {
  83.     register struct hapn *hp;
  84.     register int16 base;
  85.     char flag = 0;
  86.  
  87.     hp = &Hapn[dev];
  88.     base = hp->base;
  89.  
  90.     /*  Check for TX interrupt  */
  91.     if(inportb(base+STA) & TXINT){
  92.         flag = 1;    /* Valid interrupt, set flag */
  93.         htxint(hp);
  94.     }
  95.     /*  Check for RX interrupt  */
  96.     if(inportb(base+STA) & RXINT){
  97.         flag = 1;    /* Valid interrupt, set flag */
  98.         hrxint(hp);
  99.     }
  100.     /* Check for unknown interrupt  */
  101.     if(!flag){
  102.         hp->badint++;    /* Increment error counter */
  103.         hapn_init(hp);    /* Reinitialise the 8273 */
  104.     }
  105. }
  106. /*  RX interrupt service
  107.  *  if status register bit "RXIRA" is set, interrupt is final,
  108.  *  otherwise, interrupt is data request
  109.  */
  110. static void
  111. hrxint(hp)
  112. register struct hapn *hp;
  113. {
  114.     register struct mbuf *bp;
  115.     register int16 base;
  116.     unsigned char results[10];
  117.     struct phdr phdr;
  118.  
  119.     hp->rxints++;
  120.     base = hp->base;
  121.  
  122.     if(inportb(base+STA) & RXIRA){
  123.         /* RX result interrupt
  124.          * If the result is a good frame 3 bytes need to be read
  125.          * If an error has occurred only one byte need to be read
  126.          */
  127.  
  128.         /* Read first result byte and test for good data */
  129.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  130.             /* Good result; read two more result bytes */
  131.             while((inportb(base + STA) & RXIRA) == 0)
  132.                 ;
  133.             /* Read second result byte */
  134.             results[1] = inportb(base + RXI);
  135.             /* Wait for third result byte  */
  136.             while((inportb(base + STA) & RXIRA) == 0)
  137.                 ;  
  138.             results[2] = inportb(base + RXI);/* Read it */
  139.  
  140.             /* Since this frame is ok put it on the queue */
  141.             bp = alloc_mbuf(sizeof(phdr));
  142.             bp->cnt = sizeof(phdr);
  143.             phdr.iface = hp->iface;
  144.             phdr.type = CL_AX25;
  145.             memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  146.             bp->next = hp->rcvbuf;
  147.             hp->rcvbuf = NULLBUF;
  148.             enqueue(&Hopper, bp);
  149.             hp->rframes++;
  150.         } else {
  151.             /* Error termination
  152.              * Parse RIC and act accordingly
  153.              * Only one result byte returned on error
  154.              */
  155.             switch(results[0]){
  156.             case CRCERR:
  157.                 hp->crcerr++;
  158.                 break;
  159.             case ABORT_DET:
  160.                 hp->aborts++;
  161.                 break;
  162.             case DMA_OVRN:
  163.                 hp->dmaorun++;
  164.                 break;
  165.             case MEM_OVFL:
  166.                 hp->toobig++;
  167.                 break;
  168.             case CD_LOSS:
  169.                 hp->cdloss++;
  170.                 hapn_init(hp);    /* 8273 reset on cd error */
  171.                 break;
  172.             case RX_ORUN:
  173.                 hp->rxorun++;
  174.                 break;
  175.             }
  176.             /* Throw rx buffer contents away to start over */
  177.             hp->rcp = hp->rcvbuf->data;
  178.             hp->rcvbuf->cnt = 0;
  179.         }
  180.         /* Restart the receiver */
  181.         cmd_8273(base,RX_DISABLE,0);
  182.         hrxgo(hp);
  183.     } else {
  184.         /* RX data interrupt; allocate new rx buffer if none present */
  185.         if((bp = hp->rcvbuf) == NULLBUF){
  186.             bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  187.             if(bp == NULLBUF){
  188.                 /* No memory available */
  189.                 hp->nomem++;
  190.                 cmd_8273(base, RX_DISABLE, 0);
  191.                 hrxgo(hp);
  192.                 return;
  193.             }
  194.             /* Init buffer pointer */
  195.             hp->rcp = hp->rcvbuf->data;
  196.         }
  197.         /*  Barf if rx data is more than buffer can hold (should never
  198.          *  happen since 8273 is also counting bytes).
  199.          */
  200.         if(bp->cnt++ >= hp->bufsiz){
  201.             hp->toobig++;
  202.             cmd_8273(base, RX_DISABLE, 0);
  203.             hrxgo(hp);
  204.             free_p(bp);
  205.             hp->rcvbuf = NULLBUF;
  206.             return;
  207.         }
  208.         /* Store the received byte */
  209.         *hp->rcp++ = inportb(base+RXD);
  210.     }
  211. }
  212.  
  213. /*  test for busy channel (CD active)
  214.  *  returns TRUE if channel busy
  215.  */
  216. static int
  217. hcdchk(base)
  218. int16 base;
  219. {
  220.     char isav;
  221.  
  222.     isav = disable ();
  223.     cmd_8273(base, READ_A, 0);
  224.     while(!(inportb(base+STA) & CRBF))
  225.         ;
  226.     restore(isav);
  227.     return((inportb(base+RES) & CD) != 0);
  228. }
  229.  
  230. /*  TX interrupt service
  231.  *  if status register bit "TXIRA" is set, interrupt is final,
  232.  *  otherwise, interrupt is data request
  233.  */
  234. static void
  235. htxint(p)
  236. void *p;
  237. {
  238.     register struct hapn *hp;
  239.     char isav;
  240.     register int16 base;
  241.     int16 len;
  242.     int c;
  243.  
  244.     hp = (struct hapn *)p;
  245.     isav = disable ();
  246.     hp->txints++;
  247.     base = hp->base;
  248.  
  249.     c = 0;
  250.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  251.         hp->tstate = IDLE;
  252.         free_p(hp->sndbuf);
  253.         hp->sndbuf = NULLBUF;
  254.  
  255.         /*  Read result  */
  256.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  257.             ;
  258.         c = inportb(base+TXI);
  259.  
  260.         /*  Test for tx abort  */
  261.         switch(c & 0x1f){
  262.         case DMA_URUN:
  263.             hp->t_urun++;
  264.             break;
  265.         case CTS_LOSS:
  266.             hp->ctsloss++;
  267.             break;
  268.         case ABORT_CMPLT:
  269.             hp->taborts++;
  270.             break;
  271.         }
  272.     }
  273.     switch(hp->tstate){
  274.     case IDLE:    /*  See if a buffer is ready to be sent  */
  275.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  276.             break;
  277.  
  278.     case DEFER:    /*  Busy-channel check  */
  279.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  280.             if(hcdchk(base)){
  281.                 hp->tstate = DEFER;
  282.                 start_timer(&hp->defer);
  283.                 break;
  284.             }
  285.         }
  286.         /*  Start transmitter  */
  287.         stop_timer(&hp->defer);
  288.         len = len_p(hp->sndbuf);
  289.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  290.         hp->tstate = ACTIVE;
  291.         hp->tframes++;
  292.         break;
  293.     case ACTIVE:    /*  Get next byte to send  */
  294.         if((c = PULLCHAR(&hp->sndbuf)) == -1){
  295.             cmd_8273(base, ABORT_TXF, 0);
  296.             hp->tstate = IDLE;
  297.         } else
  298.             outportb(base+TXD, c);
  299.         break;
  300.     }
  301.     restore(isav);
  302. }
  303.  
  304. /*  Attach a HAPN adaptor to the system
  305.  *  argv[0]:  hardware type, must be "hapn"
  306.  *  argv[1]:  I/O address, e.g. "0x310"
  307.  *  argv[2]:  vector, e.g. "2"
  308.  *  argv[3]:  mode, must be "ax25"
  309.  *  argv[4]:  interface name, e.g. "ha0"
  310.  *  argv[5]:  rx packet buffer size in bytes
  311.  *  argv[6]:  maximum transmission unit in bytes
  312.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  313.  *  argv[8]: IP address, optional (defaults to Ip_addr)
  314.  */
  315. int
  316. hapn_attach(argc, argv,p)
  317. int argc;
  318. char *argv[];
  319. void *p;
  320. {
  321.     register struct iface *if_h;
  322.     struct hapn *hp;
  323.     int dev, i;
  324.     char isav;
  325.     static struct {
  326.         char *str;
  327.         char type;
  328.     } ch_access [] = { "csma", 0, "full", 1 };
  329.  
  330.     if(Nhapn >= NHAPN){
  331.         tputs("Too many HAPN adaptors\n");
  332.         return -1;
  333.     }
  334.     if(if_lookup(argv[4]) != NULLIF){
  335.         tprintf(Existingiface,argv[4]);
  336.         return -1;
  337.     }
  338.     /*  Create new interface structure  */
  339.     if_h = (struct iface *) callocw(1,sizeof(struct iface));
  340.  
  341.     /*  Set interface address  */
  342.     if_h->addr = Ip_addr;
  343.     if(argc > 8)
  344.         if_h->addr = resolve(argv[8]);
  345.     if(if_h->addr == 0){
  346.         tputs(Noipaddr);
  347.         free((char *)if_h);
  348.         return -1;
  349.     }
  350.     dev = Nhapn++;
  351.     hp = &Hapn[dev];
  352.  
  353.     /*  Initialize hardware constants */
  354.     hp->base = htoi(argv[1]);
  355.     hp->vec = htoi(argv[2]);
  356.  
  357.     /*  Save original interrupt vector  */
  358.     hp->oldvec = getirq(Hapn[dev].vec);
  359.  
  360.     /*  Set new interrupt vector  */
  361.     setirq(hp->vec, H_handle[dev]);
  362.  
  363.     /* Continue filling interface structure */
  364.     if_h->name = strdup(argv[4]);
  365.     if_h->iface_metric = 1;
  366.     if_h->type = CL_AX25;
  367.     if_h->mtu = atoi(argv[6]);
  368.     if_h->dev = dev;
  369.     if_h->stop = hapn_stop;
  370.     if_h->output = ax_output;
  371.     if_h->raw = hapn_raw;
  372.     hp->iface = if_h;
  373.  
  374.     if(strcmp(argv[3], "ax25")){
  375.         tprintf("Mode %s unknown for interface %s\n", argv[3], argv[4]);
  376.         free(if_h->name);
  377.         free((char *) if_h);
  378.         return -1;
  379.     }
  380.     if(Mycall[0] == '\0'){
  381.         tputs("set mycall first\n");
  382.         free(if_h->name);
  383.         free((char *) if_h);
  384.         return -1;
  385.     }
  386.     if_h->send = ax_send;
  387.     if(if_h->hwaddr == NULLCHAR)
  388.         if_h->hwaddr = mallocw(AXALEN);
  389.     memcpy(if_h->hwaddr,Mycall,AXALEN);
  390.     if(if_h->ipcall == NULLCHAR)
  391.         if_h->ipcall = mallocw(AXALEN);
  392.     memcpy(if_h->ipcall,Mycall,AXALEN);
  393.     /*  Link the interface into the interface list  */
  394.     if_h->next = Ifaces;
  395.     Ifaces = if_h;
  396.  
  397.     /*  Fill the local data structure  */
  398.     hp->bufsiz = atoi(argv[5]);
  399.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  400.         if(!strcmp(argv[7], ch_access[i].str))
  401.             hp->mode = ch_access[i].type;
  402.  
  403.     /*  Initialize the hardware  */
  404.     isav = disable ();
  405.     hapn_init(hp);
  406.  
  407.     /* Initialize the defer timer */
  408.     set_timer(&hp->defer,MSPTICK);
  409.     hp->defer.func = htxint;
  410.     hp->defer.arg = hp;
  411.  
  412.     /*  Enable the interrupt  */
  413.     maskon(hp->vec);
  414.  
  415.     restore(isav);
  416.     return 0;
  417. }
  418.  
  419. /*  initialize the HAPN adaptor */
  420. static int
  421. hapn_init(hp)
  422. register struct hapn *hp;
  423. {
  424.     register int16 base;
  425.     char isav;
  426.  
  427.     isav = disable ();
  428.     base = hp->base;
  429.  
  430.     /*  Reset the 8273 */
  431.     outportb(base+RST, 1);
  432.     outportb(base+RST, 0);
  433.     inportb(base+TXI);        /* Clear any old IR contents */
  434.     inportb(base+RXI);
  435.  
  436.     /*  Select the operating modes  */
  437.     cmd_8273(base, SET_XFER, 1, 1);
  438.     cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  439.     cmd_8273(base, SET_SERIAL, 1, NRZI);
  440.     cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  441.     cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  442.     hrxgo(hp);
  443.     restore(isav);
  444.     return 0;
  445. }
  446.  
  447. /*  shut down the HAPN adaptor */
  448. static int
  449. hapn_stop(iface)
  450. struct iface *iface;
  451. {
  452.     int dev;
  453.     int16 base;
  454.     struct hapn *hp;
  455.  
  456.     dev = iface->dev;
  457.     hp = &Hapn[dev];
  458.     base = hp->base;
  459.  
  460.     /*  Mask off interrupt input  */
  461.     maskoff(hp->vec);
  462.  
  463.     /*  Restore original interrupt vector  */
  464.     setirq(hp->vec,hp->oldvec);
  465.  
  466.     /*  Reset the 8273  */
  467.     outportb(base+RST, 1);
  468.     outportb(base+RST, 0);
  469.     return 0;
  470. }
  471.  
  472. /* Display adaptor statistics */
  473. int
  474. dohapnstat(argc,argv,p)
  475. int argc;
  476. char *argv[];
  477. void *p;
  478. {
  479.     struct hapn *hp;
  480.     int i;
  481.  
  482.     if(Nhapn == 0){
  483.         tputs("No HAPN adaptor attached\n");
  484.         return 1;
  485.     }
  486.     for(i = 0; i < Nhapn; i++){
  487.         hp = &Hapn[i];
  488.         tprintf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5d\n", i,
  489.          hp->rxints,hp->txints,hp->badint);
  490.         tprintf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5d\n",
  491.          hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  492.         tprintf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5d\n",
  493.          hp->toobig,hp->cdloss,hp->rxorun);
  494.         if(tprintf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5d\n",
  495.          hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss) == EOF)
  496.             break;
  497.     }
  498.     return 0;
  499. }
  500.  
  501. /* Send raw packet on HAPN interface */
  502. static int
  503. hapn_raw(iface,bp)
  504. struct iface *iface;
  505. struct mbuf *bp;
  506. {
  507.     struct hapn *hp;
  508.  
  509.     hp = &Hapn[iface->dev];
  510.     enqueue(&hp->sndq, bp);
  511.  
  512.     /*  See if anything being transmitted  */
  513.     if(hp->tstate == IDLE)
  514.         htxint(hp);
  515.     return 0;
  516. }
  517. #endif /* HAPN */
  518. #endif /* MSDOS */
  519.  
  520.